/**
* 
* Entity : super class for all entities 
* Copyright (c) 2009 Ecole Centrale de Nantes IRCCyN  
* 
* see <a href="{@docRoot}/Documentation/data.html"> for more information</a>
* 
* @author: Urunuela Richard
* @version 3.2
*/
package storm;

import java.awt.Color;
import java.beans.XMLEncoder;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import javax.swing.JOptionPane;

import log.messageTrace;

import report.classSonde;
import storm.Entity;
import storm.Processors.Processor;
import storm.Schedulers.Scheduler;
import storm.Tasks.Task;


public abstract class Entity  implements Cloneable{
	protected ISimulationKernel Kernel;
	public int   debug = -1;
	public boolean log = false;
	public Color color;
	public String name="NA";
	public int id=-1;
	protected Hashtable ownField;
	protected classSonde mySonde=null;
/**
 * 
 * @return
 */
	public void setKernel(ISimulationKernel iSimulationKernel){
		this.Kernel=iSimulationKernel;
	}
	public ISimulationKernel getKernel(){
		return this.Kernel;
	}
	public int getId() {
		return id;
	}
	
	/**
	 * 
	 * @return
	 */
	public classSonde getMySonde() {
		return mySonde;
	}
	/**
	 * 
	 * @param mySonde
	 */
	public void setMySonde(classSonde mySonde) {
		this.mySonde = mySonde;
	}
	/**
	 * 
	 * @param id
	 */
	public void setId(int id) {
		this.id = id;
	}
	/**
	 * Own  additionnal field compute with XML file for example
	 * @return
	 */
	public Vector getOwnFileds(){
		Vector res = new Vector();
		this.ownField.size();
		 Set en = this.ownField.keySet();  
		 Iterator I = en.iterator() ;
		 Vector l1 = null;
		 while (I.hasNext()){
			  l1 = new Vector();
			 Object A = I.next();
			 l1.add(A.toString());
			 l1.add((this.ownField.get(A)).toString());
			 res.add(l1);
		 }
		 return res;
	}
	/**
	 * own field add new one
	 * @param name
	 * @param value
	 */
	public void addNewField(String name,String value){
		this.ownField.put(name,value);
		
	}
	/**
	 * own field get  one value in string
	 * @param name
	 * @return
	 */
	public String getOwnFieldStringValue(String name) {
		if (this.ownField.get(name ) == null )  System.out.println(" ERROR " + name + " Not know ");

		return (String)this.ownField.get(name);
	}
/**
 * own field get  one value in int
 * @param name
 * @return
 */
	public int getOwnFieldIntValue(String name) {
		int res=1;
		try{
		res = Integer.valueOf((String)this.ownField.get(name)).intValue();
		}
		catch (NumberFormatException  e){
			System.out.println("ERROR" + name + " from " + this.toString());
			JOptionPane.showMessageDialog(null,
				    "Parse Error acces to xml attribut(check xml file) " + name + " from " + this.toString() + " Simulation Stopped" ,
				    name,
				    JOptionPane.ERROR_MESSAGE);
			this.Kernel.stop();
		}
		return res;
	}
	public short getOwnFieldShortValue(String name) {
		short res=1;
		try{
		res = Short.parseShort((String)this.ownField.get(name));
		}
		catch (NumberFormatException  e){
			System.out.println("ERROR" + name + " from " + this.toString());
			JOptionPane.showMessageDialog(null,
				    "Parse Error acces to xml attribut(check xml file) " + name + " from " + this.toString() + " Simulation Stopped" ,
				    name,
				    JOptionPane.ERROR_MESSAGE);
			this.Kernel.stop();
		}
		return res;
	}
	public float getOwnFieldFloatValue(String name) {
		float res=1;
		try{
		res = Float.parseFloat((String)this.ownField.get(name));
		}
		catch (NumberFormatException  e){
			System.out.println("ERROR" + name + " from " + this.toString());
			JOptionPane.showMessageDialog(null,
				    "Parse Error acces to xml attribut(check xml file) " + name + " from " + this.toString() + " Simulation Stopped" ,
				    name,
				    JOptionPane.ERROR_MESSAGE);
			this.Kernel.stop();
		}
		return res;
	}
	public double getOwnFieldDoubleValue(String name) {
		double res=1;
		try{
		res = Double.parseDouble((String)this.ownField.get(name));
		}
		catch (NumberFormatException  e){
			System.out.println("ERROR" + name + " from " + this.toString());
			JOptionPane.showMessageDialog(null,
				    "Parse Error acces to xml attribut(check xml file) " + name + " from " + this.toString() + " Simulation Stopped" ,
				    name,
				    JOptionPane.ERROR_MESSAGE);
			this.Kernel.stop();
		}
		return res;
	}
	public boolean getOwnFieldBooleanValue(String name) {
		boolean  res=false;
		try{
		if (this.ownField.get(name) != null ) {
			res = Boolean.parseBoolean((String)this.ownField.get(name));
		}
		else 
			res = false;
		}
		catch (NumberFormatException  e){
			System.out.println("ERROR" + name + " from " + this.toString());
			JOptionPane.showMessageDialog(null,
				    "Parse Error acces to xml attribut(check xml file) " + name + " from " + this.toString() + " Simulation Stopped" ,
				    name,
				    JOptionPane.ERROR_MESSAGE);
			this.Kernel.stop();
		}
		return res;
	}
	/**
	 * get onwnfiled
	 * @return
	 */
	public Hashtable getOwnField() {
		return ownField;
	}
	/**
	 *  
	 * @param ownField
	 */
	public void setOwnField(Hashtable ownField) {
		this.ownField = ownField;
	}
	/**
	 * 
	 * @param nodeName
	 * @param nodeValue
	 */
	public void setOwnFieldStringValue(String nodeName, String nodeValue) {
		// TODO Auto-generated method stub
		this.ownField.remove(nodeName);
		this.ownField.put(nodeName,nodeValue);
	}
	
	/**
	 * 
	 * @param string
	 * @param i
	 */
	public void setOwnFieldIntValue(String string, int i) {
		this.ownField.remove(string);
		
		this.ownField.put(string,(i+""));
		// TODO Auto-generated method stub
		
	}
	public void setOwnFieldShortValue(String string, short  i) {
		this.ownField.remove(string);
		
		this.ownField.put(string,(i+""));
		// TODO Auto-generated method stub
		
	}
	public void setOwnFieldDoubleValue(String string, double i) {
		this.ownField.remove(string);
		
		this.ownField.put(string,(i+""));
		// TODO Auto-generated method stub
		
	}
	public void setOwnFieldFloatValue(String string, float i) {
		this.ownField.remove(string);
		
		this.ownField.put(string,(i+""));
		// TODO Auto-generated method stub
		
	}
	public void setOwnFieldBooleanValue(String string, boolean i) {
		this.ownField.remove(string);
		
		this.ownField.put(string,(i+""));
		// TODO Auto-generated method stub
		
	}
	/**
	 * 
	 */
	public Entity(){
		this.ownField = new Hashtable();
	}
	/**
	 * 
	 */
	public int getTime(){
		return 0;
	}
	/**
	 * 
	 */
	public void debug_mess(String info,int level){
		if (level <= debug){
			System.out.println("[DEBUG " + level + "  ] " + Kernel.getTime()  + " " + info);
	
		}
		
	}
	
	/**
	 * 
	 * V 4
	 */
	public String getAllFiedl(){
		String res = "";
		// instropection
		Class c = this.getClass();
		Field[] f = c.getFields();
		for (int i =0; i <f.length; i ++) {
			res = res + (f[i]).getName() + "\t   //" + (f[i]).getType().getCanonicalName() +  "\n";
		}
		
		
		//Ownfiled
	

		Enumeration enu=ownField.keys();
		while(enu.hasMoreElements())
		{
		  Object o=enu.nextElement();
		  res = res + (o.toString()) + " \t  //" + o.getClass().getCanonicalName()+ "\n";
		  //ownField.get(o);
		  
		}
		
		
		return res;
		
	}

	public String toString(){
		
		
		
		
		return super.toString();
	}
	/**
	 * 
	 * @param e
	 * @return
	 */
	public String toXMl(  XMLEncoder e){
		return ("<ENTITY> " +this.toString()+" </ENTITY>");
	}
	/**
	 * Processing message 
	 * @see <a href="{@docRoot}/Documentation/data.html"> for more information</a>
	 * @param m
	 */
	public void processingMessage(KernelMessage m){
		/**
		 * Activate message 
		 */
		this.Kernel.getLogs().addTrace(new messageTrace(this.Kernel.getTime(),m.S,m.D,m.type, messageTrace.Type.PROCESSING));
		if (m.type ==  KernelMessage.value.ACTIVATE ) {
			/*
			 *message en provenance du TLM vers Task 
			 */
			if ((m.S instanceof TasksListeManager) && (m.D instanceof Task) ){
				debug_mess("[Wrapper Messsage ACTIVATE de TLM pour Task ]",10);
				/**
				 * Activate Task
				 */
				m.D.onActivate((EvtContext)m);
				/**
				 *Activate Scheduler 
				 */
				m.param1.onActivate((EvtContext)m);
			}

		}
		/**
		 *Blocage fonctionnelle 
		 */
		if (m.type == KernelMessage.value.UNREADY) {
			debug_mess("[Wrapper Messsage UNREADY de "+ m.S +" pour " + m.D +" ]",10);
			m.D.onBlock(m.S,(EvtContext) m);
			if (((Task)m.D).scheduler != null){
				((Task)m.D).scheduler.onUnReady((EvtContext)m);
			}
		}
		/**
		 * Block 
		 */
		if (m.type == KernelMessage.value.BLOCK) {
			debug_mess("[Wrapper Messsage BLOCK de "+ m.S +" pour " + m.D +" ]",10);
				Task T= (Task) m.D;
				m.D.onBlock(m.S,(EvtContext) m);
			if (((Task)m.D).scheduler != null){
				/**
				 *
				 * Attention cas d'un contr??le de data alors que la t??che consomatrice n'est pas encore activ??
				 * donc scheduler == null :(
				 */
				((Task)m.D).scheduler.onBlock((EvtContext)m);
			}
		}
		/**
		 * Un block 
		 */
		if (m.type == KernelMessage.value.UNBLOCK) {
			debug_mess("[Wrapper Messsage UNBLOCK de "+ m.S +" pour " + m.D +" ]",10);
			
			if (m.D instanceof Scheduler ) {
				Task T= (Task) m.S;
				m.D.onUnBlock((EvtContext)m);
			}
			else m.D.onUnBlock(m.S, (EvtContext)m);
		}
		/**
		 *		Terminated 
		 */
		if (m.type == KernelMessage.value.TERMINATE) {
	
			debug_mess("[Wrapper Messsage TERMINATED de " + m.S +" pour " + m.D +" ]",10);
			Task T =(Task)m.D;
	
			T.setUnexisting();
			T.scheduler.onTerminated((EvtContext)m);
		}
	}
	
	/**
	 * message d??clench?? pat le TLM
	 */
	public void raiseTerminated(){
		debug_mess("[Raise Terminated Record message] "+ this ,10);
		KernelMessage M =  new KernelMessage(this,this, KernelMessage.value.TERMINATE );
		this.Kernel.addMessage(M);
	}
	/**
	 * 
	 * @param T
	 * @param S
	 */
	public void raiseActivate(Task T ,Scheduler S){
		debug_mess("[Raise Activate Record message] "+ this ,10);
		KernelMessage M =  new KernelMessage(this,T, KernelMessage.value.ACTIVATE ,S);
		this.Kernel.addMessage(M);
		
	}
	/**
	 * 
	 * @param A
	 */
	public void raiseBlock(Entity A){
		debug_mess("[Raise Block  Task  message] "+ A  + " from " + this,10);	
		KernelMessage m = new KernelMessage(this,A,KernelMessage.value.BLOCK); 
		this.Kernel.addMessage(m);
		
	}
	/**
	 * 
	 */
	public void raiseBlock(){
	
		debug_mess("[Raise Block  Task REcord message] "+ this ,10);	
		KernelMessage m = new KernelMessage(this,this,KernelMessage.value.BLOCK); 
		this.Kernel.addMessage(m);
		
	}
	/**
	 * 
	 * @param A
	 */
	public void raiseUnReady(Entity A){
		debug_mess("[Raise Block  Task REcord message] "+ this ,10);	
		KernelMessage m = new KernelMessage(this,A,KernelMessage.value.UNREADY); 
		this.Kernel.addMessage(m);
		
	}
	/**
	 * unblock me 
	 */
	public void raiseUnBlock(){

		debug_mess("[Raise UnBlock Task   REcord message] "+ this ,10);	
		KernelMessage m = new KernelMessage(this,this,KernelMessage.value.UNBLOCK); 
		this.Kernel.addMessage(m);
	}
	/**
	 * unblock another entity
	 * @param A
	 */
	public void raiseUnBlock(Entity A){
		debug_mess("[Raise Block  REcord message] "+ this ,10);	
		KernelMessage m = new KernelMessage(this,A,KernelMessage.value.UNBLOCK); 
		this.Kernel.addMessage(m);
	}
	/**
	 * 
	 * @param c
	 */
	public void onBlock(EvtContext c){
	}
	/**
	 * 
	 * @param E
	 * @param c
	 */
	public void onBlock(Entity E, EvtContext c){
	}
	/**
	 * 
	 * @param c
	 */
	public void onUnBlock(EvtContext c){
	}
	/**
	 * 
	 * @param E
	 * @param c
	 */
	public void onUnBlock(Entity E, EvtContext c){
	}
	/**
	 * 
	 * @param c
	 */
	public void onActivate(EvtContext c) {
	}
	/**
	 * 
	 */
	public void onTerminated() {
	}
	/**
	 * 
	 * @param c
	 */
	public void onTerminated(EvtContext c) {
	}
	/**
	 * 
	 * @param c
	 */
	public void onUnReady(EvtContext c) {
	}
	/**
	 * Unit?? de mesure du temps 
	 * Touts les une unit?? de temps on peut d??clencher un evt
	 */
	public void onTick(){
	}
	/**
	 * init element afer construction before start simulation
	 * @throws Exception 
	 */
	public void init() {
		if (this.Kernel.getAllTrace()){
			/**
			 * create file InternalState from sonde
			 */
				 mySonde = new classSonde(this);
			}
	}
	/**
	 * 
	 * @return
	 */
	public String getName() {
		return name;
	}
	/**
	 * 
	 * @param name
	 */
	public void setName(String name) {
		this.name = name;
	}
	/**
	 * 
	 * @return
	 */
	public Color getColor() {
		return color;
	}
	/**
	 * 
	 * @param color
	 */
	public void setColor(Color color) {
		this.color = color;
	}
	/**
	 * 
	 * @return
	 */
	public String SondetoString() {
		return null;
	}

	public void freeAll() {
		// TODO Auto-generated method stub
		
	}

	
	//CLone
	public Object  clone() {
		Entity  O=null;
		try {
			O = (Entity) super.clone();
	
			O.setColor(this.color);
			
			O.mySonde = new classSonde(O);
			O.ownField = (Hashtable) this.ownField.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return O;
		
	}
	
	
}
